package {
	import org.flixel.*;
	
	public class Board extends FlxGroup {
		
		public var blockgrid:Array, capacity:int, boardSize:int, score:int = 0, goal:int, scatterTime:int = 3, combo:int = 0 ;
		private const PIXEL_SIZE:int = 32;
		private var timeText:FlxText, scoreText:FlxText, endingText:FlxText, comboText:FlxText;
		private var playmode:Boolean, misclicked:Boolean, newGameButton:FlxButton;
		
		[Embed(source = "../assets/rightalign.png")] protected var rightalign:Class; 
		[Embed(source = "../assets/leftalign.png")] protected var leftalign:Class; 
		[Embed(source = "../assets/cursor.png")] protected var cursorg:Class; 
		[Embed(source = "../assets/pot.png")] protected var potg:Class
		[Embed(source = "../assets/aim.png")] protected var aimg:Class;
		
		private var cursor:FlxSprite = new FlxSprite();
		private var pot:FlxSprite = new FlxSprite();
		private var ClickedPoint:FlxPoint = new FlxPoint();
		private var partiGroup:FlxGroup = new FlxGroup();
		private var tileGroup:FlxGroup = new FlxGroup();
		private var GameTimer:FlxTimer = new FlxTimer();
		
		public function Board(size:int, congestion:int, t:int, g:int) {
			FlxG.mouse.hide();
			blockgrid = new Array(size);
			timeText = new FlxText(FlxG.width - 400, FlxG.height - 80, 300, "Time: "+t.toString());
			timeText.size = 20;
			
			
			comboText = new FlxText(FlxG.width - 575, FlxG.height - 80, 300, combo.toString() +"x Combo!");
			comboText.size = 20;
			
			scoreText = new FlxText(FlxG.width - 225, FlxG.height - 80, 300, "Score: "+score.toString());
			scoreText.size = 20;
			
			
			var i:int ;
			for (i = 0; i < size; i++) {
				blockgrid[i] = new Array(size);
			}
			capacity = size * size;
			
			drawGrid(size);
			fillWithBlocks(congestion);
			
			cursor.loadGraphic(cursorg);
			pot.loadGraphic(potg);
			
			boardSize = blockgrid.length;
			goal = g;
			
			pot.x = (size * PIXEL_SIZE) + 5;
			pot.y = (size * PIXEL_SIZE) + 5;
			
			this.add(pot) ;
			this.add(comboText);
			this.add(cursor);
			this.add(timeText);
			this.add(scoreText);
			this.add(tileGroup);
			playmode = true; misclicked = false;
			GameTimer.start(t, 1, GameEndHelper);
		}
		
		private function GameEndHelper(Timer:FlxTimer):void {
			playmode = false;
			FlxG.mouse.show();
			var finishUp:FlxTimer = new FlxTimer();
			finishUp.start(scatterTime + 1, 1, GameEnd);
		}
		
		private function GameEnd(Timer:FlxTimer):void {
			for each (var b:BasicBlock in tileGroup.members) {
				if(b != null) tileGroup.remove(b);
			}
			scoreText.text = score.toString();
			endingText = new FlxText((FlxG.width / 2) - 300, (FlxG.height / 2) - 200, 500, "Your score is");
			endingText.size = 50;
			scoreText.x = (FlxG.width / 2) - 300;
			scoreText.y = (FlxG.height / 2) - 150;
			scoreText.size = 50;
			scoreText.draw();
			newGameButton = new FlxButton((FlxG.width / 2) - 100 , (FlxG.height / 2), "New Game", newGame);
			
			newGameButton.draw();
			add(endingText);
			add(newGameButton);
			
			
		}
		
		private function resetMisclick(Timer:FlxTimer):void {
			misclicked = false;
			timeText.color = 0xffffffff;
		}
		
		private function newGame():void{
			FlxG.switchState(new DifficultySettingState);
		}
		
		
		private function drawGrid(length:int):void {
			var flag:Boolean = true;
			for (var i:int = 0; i < length; i++) {
				for (var j:int = 0; j < length; j++) {
					var spriteA:FlxSprite = new FlxSprite(PIXEL_SIZE*i, PIXEL_SIZE*j);
					if (flag) {
						spriteA.loadGraphic(leftalign, true, true, PIXEL_SIZE);
					}else {
						spriteA.loadGraphic(rightalign, true, true, PIXEL_SIZE);
					}
					this.add(spriteA);
					flag = !flag;
				}
				if(length%2==0)flag = !flag;
			}
		}
		
		/** fill with blocks
		 * (density value 0 - 9)
		 */
		private function fillWithBlocks(density:int):void {
			var amount:int;
			amount = (capacity * density) / 10;
			var rows:int, cols:int, color:int;
			while (amount > 1) {
				var firstBlock:BasicBlock;
				rows = Math.round(Math.random() * (blockgrid.length - 1));
				cols = Math.round(Math.random() * (blockgrid.length - 1));
				if (blockgrid[rows][cols] == null) {
					blockgrid[rows][cols] = new BasicBlock(rows, cols);
					firstBlock = blockgrid[rows][cols];
					blockgrid[rows][cols].x = rows * PIXEL_SIZE;
					blockgrid[rows][cols].y = cols * PIXEL_SIZE;
					tileGroup.add(blockgrid[rows][cols]);
					amount --;
				}
				//provide a matching color tile
				rows = Math.round(Math.random() * (blockgrid.length - 1));
				cols = Math.round(Math.random() * (blockgrid.length - 1));
				if (blockgrid[rows][cols] == null) {
					blockgrid[rows][cols] = new BasicBlock(rows, cols);
					blockgrid[rows][cols].setType(firstBlock.getType());
					blockgrid[rows][cols].x = rows * PIXEL_SIZE;
					blockgrid[rows][cols].y = cols * PIXEL_SIZE;
					tileGroup.add(blockgrid[rows][cols]);
					amount --;
				}
			}
		}
		
		
		private function returnBlockInSpot(ex:int, wy:int):BasicBlock {
			return blockgrid[ex][wy];
		}
		
		
		private function isBlockInSpot():Boolean {
			return returnBlockInSpot(Math.floor(FlxG.mouse.x / PIXEL_SIZE), Math.floor(FlxG.mouse.y / PIXEL_SIZE)) != null;
		}
		
		
		private function destroyMatch(group:FlxGroup):void {
			var i:int, deleteGroup:FlxGroup = new FlxGroup();
			for (i = 0 ; i < group.length; i++) {
				var block:BasicBlock = group.members[i];
				for (var j:int = i + 1; j < group.length; j++) {
					var block2:BasicBlock = group.members[j];
					if (block.getType() == block2.getType()) {
						deleteGroup.add(block2);
						deleteGroup.add(block);
					}
				}
			}
			if (deleteGroup.members.length == 0 && playmode && !misclicked) {
				misclicked = true;
				GameTimer.time = GameTimer.timeLeft - 20;
				var misClickTimer:FlxTimer = new FlxTimer();
				timeText.color = 0xffFF0000;
				misClickTimer.start(1, 1, resetMisclick);
				comboText.visible = false;
			}
			else {
				this.combo ++;
			}
			explode(deleteGroup.members);
			for each (var b:BasicBlock in deleteGroup.members) {
				tileGroup.remove(b);
				blockgrid[b.r][b.c] = null;
				b.destroy();
			}
		}
		
		private function displayCombo():void {
			comboText.visible = true;
			comboText.size = 20 + (combo * 1.1);
			comboText.text = combo.toString() + "x Combo!";
			comboText.color = comboText.color + combo*50
		}
		
		
		private function followPartPath(Timer:FlxTimer):void {
			var partPath:FlxPath = new FlxPath(new Array(ClickedPoint, new FlxPoint(pot.x+32, pot.y+32)));
			
			score = (score + Math.pow(partiGroup.members.length, 1.05)) / 10;
			score *= 10;
			
			for each(var p:FlxParticle in partiGroup.members) {
				if (p != null) {
					p.followPath(partPath, 250);
				}
			}
			this.combo = 0;
			partiGroup = new FlxGroup();
		}
		
		
		private function explode(blocks:Array):void {
			var particles:int = 20;	
			var pathTimer:FlxTimer; 
			for each (var b:BasicBlock in blocks) {
				var emitter:FlxEmitter = new FlxEmitter(b.x + (PIXEL_SIZE/2), b.y + (PIXEL_SIZE));
				
				for (var i:int = 0; i < particles; i++){
					var particle:FlxParticle = new FlxParticle();
					b.makeParticleGraphic(particle);
					particle.exists = false;
					partiGroup.add(particle);
					emitter.add(particle);
				}
				add(emitter);
				emitter.start();
			}
			
			if (playmode) {
				pathTimer = new FlxTimer();
				pathTimer.start(scatterTime, 1, followPartPath);			
			}
		}
		
		private function getMatches():FlxGroup {
			var rows:int, cols:int;
			rows = Math.floor(FlxG.mouse.x / PIXEL_SIZE); cols = Math.floor(FlxG.mouse.y / PIXEL_SIZE);
			trace("mouse: " + rows + ", " + cols );
			var chosenGroup:FlxGroup; chosenGroup = new FlxGroup();
			var count:int; count = rows;
			while ( count > 0) {
				count --;
				if (returnBlockInSpot(count, cols) != null) {
					chosenGroup.add(returnBlockInSpot(count, cols));
					trace("block: " + count + ", " + cols );
					break;
				}
			}
			count = cols;
			while ( count > 0) {
				count --;
				if (returnBlockInSpot(rows, count) != null) {
					chosenGroup.add(returnBlockInSpot(rows, count));
					trace("block: " + rows + ", " + count );
					break;
				}
			}
			count = cols;
			while ( count < blockgrid.length - 1) {
				count ++;
				if (returnBlockInSpot(rows, count) != null) {
					chosenGroup.add(returnBlockInSpot(rows, count));
					trace("block: " + rows + ", " + count );
					break;
				}
			}
			count = rows;
			while ( count < blockgrid.length - 1) {
				count ++;
				if (returnBlockInSpot(count, cols) != null) {
					chosenGroup.add(returnBlockInSpot(count, cols));
					trace("block: " + count + ", " + cols );
					break;
				}
			}
			
			return chosenGroup;
		}
		
		
		private function mouseInRange():Boolean {
			return FlxG.mouse.x < this.boardSize * this.PIXEL_SIZE && FlxG.mouse.y < this.boardSize * PIXEL_SIZE;
		}
		
		private function maintainCursor():void {
			var maxCursorDist:int = PIXEL_SIZE * (boardSize - 1), xCursor:int = (Math.floor(FlxG.mouse.x / PIXEL_SIZE) * PIXEL_SIZE), yCursor:int = (Math.floor(FlxG.mouse.y / PIXEL_SIZE) * PIXEL_SIZE);
			
			if (xCursor > maxCursorDist) {
				cursor.x = maxCursorDist;
				FlxG.mouse.show();
			}
			else {
				cursor.x = xCursor;
			}
			if (yCursor > maxCursorDist) {
				cursor.y = maxCursorDist;
				FlxG.mouse.show();
			}
			else {
				cursor.y = yCursor;
			}
			
			if (xCursor <= maxCursorDist && yCursor <= maxCursorDist) {
				FlxG.mouse.hide();
			}
			
		}
		
		override public function update():void {
			super.update();
			tileGroup.update();
			if (GameTimer.time < 0) {
				trace("fix");
				GameTimer.time = 0.01;
			}
			if(playmode){
				maintainCursor();
				scoreText.text = "Score: " + score.toString();
				timeText.text = "Time: " + (int)(GameTimer.timeLeft).toString();
				if (combo >= 2) {
					displayCombo();
				}else {
					comboText.visible = false;
				}
			}	
			else {
				timeText.text = "Time: 0";
			}
			if (FlxG.mouse.justPressed() && mouseInRange() && !isBlockInSpot() && playmode) {
				ClickedPoint = new FlxPoint(FlxG.mouse.x, FlxG.mouse.y );
				destroyMatch(getMatches());
			}
			
				

			
		}
		
	
	}
}
			